package com.hjj.aop;

import com.hjj.beans.Stu;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


/**
 * 0、该类必须交给Spring管理
 * 1、创建一个切面类【使用@Aspect注解标注该类为切面类】
 * 2、连接点【是一个参数】【JoinPoint，环绕通知中是ProceedingJoinPoint】，主要是为了拿到目标对象的信息
 * 3、通知【执行的时机】【使用注解表达】
 * 3.1、之前【@Before】
 * 3.2、之后【@After】
 * 3.2.1、异常
 * 3.2.2、return【@AfterReturning】
 * 3.3、环绕【@Around】【ProceedingJoinPoint】
 * 4、切入点【一个表达式表达目标对象的某个方法(StuServicesImp --> doing方法)】【专门的表达式：execution()】
 * 5、目标对象【StuServicesImp --> doing方法】
 * 6、注册让注解生效
 */



@Component
@Aspect
public class MyAop {

    // 之前通知
    @Before(value = "execution(public void com.hjj.services.StuServicesImp.doing())")
    public void fun1(JoinPoint joinPoint){
        System.out.println("doing开始执行了..................");
    }


    // 之后通知
    @After(value = "execution(public void com.hjj.services.StuServicesImp.doing())")
    public void fun2(JoinPoint joinPoint){
        System.out.println("doing执行结束了..................");
    }


    // 环绕通知【需要使用ProceedingJoinPoint proceedingJoinPoint切入点来确定被切方法的执行时机】
    // 【被切方法执行时机，自己决定，使用proceedingJoinPoint.proceed();】
    @Around(value = "execution(public void com.hjj.services.StuServicesImp.doing())")
    public void fun3(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("doing环绕之前1..................");
        System.out.println("doing环绕之前2..................");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("doing环绕之后..................");
    }


    // 返回通知，可以修改引用类型的返回值，基本类型的返回值无法被修改
    @AfterReturning(value = "execution(public com.hjj.beans.Stu com.hjj.services.StuServicesImp.add())",
            returning = "re"
    )
    public void fun4(JoinPoint joinPoint, Stu re){

        re.setId(2000);
        re.setName("aaa");

        System.out.println("add第返货值是：" + re);
    }

    // 异常通知
    // 能获得异常对象
    // 不能阻止异常
    // 被切方法捕获了异常，该通知也能切到异常对象
    @AfterThrowing(value = "execution(public void  com.hjj.services.StuServicesImp.edit())",
            throwing = "e"
    )
    public void fun5(Exception e){
        System.out.println("edit的异常：" + e.getMessage());
    }


    @After(value = "execution(* com.hjj.services.StuServicesImp.del(int, int))")
    public void fun6(JoinPoint joinPoint){
        System.out.println("joinPoint.getKind():" + joinPoint.getKind());
        System.out.println("joinPoint.toLongString():" + joinPoint.toLongString());
        System.out.println("joinPoint.toShortString():" + joinPoint.toShortString());
        System.out.println("joinPoint.getSignature():" + joinPoint.getSignature());
        System.out.println("joinPoint.getSignature().getName():" + joinPoint.getSignature().getName());
        System.out.println("joinPoint.getSourceLocation():" + joinPoint.getSourceLocation());

        Object[] args = joinPoint.getArgs();
        System.out.println("第一个参数:" + args[0]);
        System.out.println("第一个参数:" + args[1]);

    }

    // 环绕通知在切入有返回值的方法，织入的业务逻辑必须具有return
    @Around(value = "execution(* com.hjj.services.StuServicesImp.del(int, int))")
    public int fun7(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        Object[] args = proceedingJoinPoint.getArgs();

        args[0] = (int)args[0] + 50;
        args[1] = (int)args[1] + 50;

        Object proceed = proceedingJoinPoint.proceed(args);

        return (int) proceed;
    }




}
